///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_CGC_H_
#define _BUOLA_IMAGE_CGC_H_

#include <buola/image/cfont.h>
#include <buola/image/cpicture.h>
#include <buola/image/ctextlayout.h>
#include <buola/image/cpattern.h>
#include <buola/image/cpath.h>
#include <cmath>
#include <buola/mat.h>

namespace buola { namespace img {

///////////////////////////////////////////////////////////////////////////
////////////////////////                         //////////////////////////
//////////////////////////      Class CGC      ////////////////////////////
/////////////////////////                       ///////////////////////////
///////////////////////////////////////////////////////////////////////////

class CGC
{
////////////////////////////////
// constructor and destructor
//
protected:
    CGC();

public:
    virtual ~CGC();
    virtual CSurface *Surface()=0;

public:
////////////////////////////////////////////////////////////////
////////////////////////// interface ///////////////////////////
////////////////////////////////////////////////////////////////

///////////
// state
//
    void ResetState();
    ///\todo
//    void PushState();
//    void PopState();
private:
    void InitState();
    
public:
////////////
// source
//
    void SetSource(const CColor &pColor)                {   mSource.SetSolid(pColor);       }
    void SetSource(CSurface*,const CPoint_d& =nZero)    {}
    void SetSource(const CLinearGradient &pGradient)    {   mSource.SetLinearGradient(pGradient); }
    void SetSource(const CRadialGradient &pGradient)    {   mSource.SetRadialGradient(pGradient); }
    void SetSourceExtend(EExtend /*pFlags*/)            {}
    void SetSourceMatrix(const mat::CMat23d &pMatrix)   {}

    const CPattern &Source() const    {   return mSource; }

//////////
// font
//
    void SetFont(PFont pFont)   {   mFont=pFont;    }
    PFont Font()                {   return mFont;   }
    void SetStockFont(const std::wstring&);

/////////////////////////
// graphics properties
//
    void SetOperator(ECompOp pOp)           {   mOp=pOp;                }
    void SetTolerance(double pTolerance)    {   mTolerance=pTolerance;  }
    void SetLineWidth(double pWidth)        {   mStroke.mWidth=pWidth;  }
    void SetLineStyle(ELineStyle pStyle)    {   mStroke.mStyle=pStyle;  }
    void SetLineCap(ELineCap pCap)          {   mStroke.mCap=pCap;      }
    void SetLineJoin(ELineJoin pJoin)       {   mStroke.mJoin=pJoin;    }

///////////////////////////
// transformation matrix
//
    void Translate(const CPoint_d &pT);
    void Rotate(double pAngle);
    void Scale(double pS);
    void Scale(const CSize_d &pSize);
    void RotateAround(const CPoint_d &pCenter,double pAngle);
    void Transform(const mat::C2DTransform &pTransform);
    void Transform(const mat::CMat23d &pTransform);
    const mat::C2DTransform &Transform() const  {   return mTransform;  }
    const mat::CMat23d &UserToDevice() const;
    const mat::CMat23d &DeviceToUser() const;

/////////////////////
// path definition
//
    CPath &Path()                       {   return mPath;   }
    const CPath &Path() const           {   return mPath;   }
    void SetPath(const CPath &pPath)    {   mPath=pPath;    }

//////////////////
// path drawing
//
    virtual void Paint()=0;

    void FillPath(bool pPreserve=false)
    {
        DoFill();
        if(!pPreserve) mPath.Reset();
    }
    
    void StrokePath(bool pPreserve=false)
    {
        DoStroke();
        if(!pPreserve) mPath.Reset();
    }
    
    void ClipPath(bool pPreserve=false)
    {
        DoClip();
        if(!pPreserve) mPath.Reset();
    }

private:
    virtual void DoFill()=0;
    virtual void DoStroke()=0;
    
    virtual void DoClip()=0;
    virtual void DoResetClip()=0;

///////////////////////
// clipping & region
//
//    virtual void ResetClipRegion()                              {}
//    virtual void SetClipRegion(const CRegion&)          {}
//    virtual void IntersectClipRegion(const CRegion&)    {}
//    virtual void PaintClipRegion()                              {}

////////////////////////
// drawing primitives
//
//    virtual void FillRegion(const CRegion &pRect);

/////////////////
// render text
//
public:
    void DrawText(const CPoint_d &pPos,const std::wstring &pText,ETextPos pPosRef=ETextPos::TOPLEFT);
    CSize_d GetTextExtents(const std::wstring &pText);

    virtual void DrawGlyphs(PFont pFont,TFontIndex pIndex,int *pIndices,int pN,
                            const std::vector<CTextLayout::SGlyph> &pGlyphs,const CPoint_d &pPos)=0;
    ///\todo implement and use this
//    virtual void DrawGlyphs(CFontInstance *pInstance,TFontIndex pIndex,int *pGlyphs,CPoint_d *pPositionsm,int pN) {}
///////////////////////
// image compositing
//
    virtual void Composite(const CPoint_d &pDstPoint,const CSize_d &pDstSize,const CPicture &pSrc,
                           const CPoint_d &pSrcPoint=nZero,const CSize_d &pSrcSize=nUndefined,
                           const CPicture &pMask=CPicture(),const CPoint_d &pMaskPoint=nZero,
                           const CSize_d &pMaskSize=nUndefined,EExtend pExtend=EExtend::NONE)=0;

/////////////////
// draw images
//
    virtual void RenderImage(const CPoint_d &pPos,const CAnyView &pView) {}
    virtual void DrawImage(const CPoint_d&,const CPicture &pPixmap);
    virtual void DrawImageRect(const CRect_d &pSrc,const CRect_d &pDst,const CPicture &pPixmap);
    virtual void DrawImageRectTiled(const CRect_d&,const CRect_d&,const CPoint_d&,const CPicture &pPixmap);
    virtual void DrawImageScaled(const CPoint_d&,const CSize_d&,const CPicture &pPixmap);
    virtual void DrawImagePart(const CRect_d&,const CPoint_d&,const CPicture &pPixmap);
    virtual void DrawImageCentered(const CRect_d&,const CPicture &pPixmap);
    virtual void DrawImageTiled(const CRect_d&,const CPoint_d&,const CPicture &pPixmap);

////////////////////
// for multi-page
//
    virtual void FlushPage(bool /*pKeep*/=false)    {}
    virtual void MakeCurrent(CSurface* =nullptr)    {}
    
protected:
    CPattern mSource;
    PFont mFont;
    ECompOp mOp;
    double mTolerance;
    CStrokeStyle mStroke;
    CPath mPath;
    mat::C2DTransform mTransform;
};

/*namespace img*/ } /*namespace buola*/ }

#endif
